package alibaba

import (
	"context"
	"os"
	"sync"
	"testing"

	"github.com/stretchr/testify/require"
	"golang.aliyun-inc.com/agit/agit/proc-receive-hook/protocol"
)

const OldOid = "5cbc82f128d4af23f500cd85625081877c9d9812"
const NewOid = "7f1a1b57413c288518a45a374478d54862eabf17"

func Test_routeCommandNoRefReviewSetting(t *testing.T) {
	for _, tc := range []struct {
		desc     string
		router   *CodeupRouter
		ref      string
		oldOid   string
		newOid   string
		pushopts map[string]string
		expected string
		env      map[string]string
	}{
		{
			desc:     "push branch without push option shall route to normal",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{},
			expected: "normal",
		},
		{
			desc:     "push new branch without push option shall route to normal",
			ref:      "refs/heads/master",
			oldOid:   NullSHA1,
			newOid:   NewOid,
			pushopts: map[string]string{},
			expected: "normal",
		},
		{
			desc:     "push new branch with push option new shall still route to normal",
			ref:      "refs/heads/master",
			oldOid:   NullSHA1,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "new"},
			expected: "normal",
		},
		{
			desc:     "push branch with review=no shall route to normal",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "no"},
			expected: "normal",
		},
		{
			desc:     "push new branch with review=no shall route to normal",
			ref:      "refs/heads/master",
			oldOid:   NullSHA1,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "no"},
			expected: "normal",
		},
		{
			desc:     "delete branch without push option shall route to normal",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NullSHA1,
			pushopts: map[string]string{},
			expected: "normal",
		},
		{
			desc:     "delete branch with push option new shall route to normal",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NullSHA1,
			pushopts: map[string]string{"review": "new"},
			expected: "normal",
		},
		{
			desc:     "delete branch with review=no shall route to normal",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NullSHA1,
			pushopts: map[string]string{"review": "no"},
			expected: "normal",
		},
		{
			desc:     "push new tag without push option shall route to normal",
			ref:      "refs/tags/v1.0",
			oldOid:   NullSHA1,
			newOid:   NewOid,
			pushopts: map[string]string{},
			expected: "normal",
		},
		{
			desc:     "push new tag with review=no shall route to normal",
			ref:      "refs/tags/v1.0",
			oldOid:   NullSHA1,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "no"},
			expected: "normal",
		},
		{
			desc:     "push new tag with review=new shall route to normal",
			ref:      "refs/tags/v1.0",
			oldOid:   NullSHA1,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "new"},
			expected: "normal",
		},
		{
			desc:     "delete tag without push option shall route to normal",
			ref:      "refs/tags/v1.0",
			oldOid:   OldOid,
			newOid:   NullSHA1,
			pushopts: map[string]string{},
			expected: "normal",
		},
		{
			desc:     "delete tag with review=no shall route to normal",
			ref:      "refs/tags/v1.0",
			oldOid:   OldOid,
			newOid:   NullSHA1,
			pushopts: map[string]string{"review": "no"},
			expected: "normal",
		},
		{
			desc:     "delete tag with review=new shall route to normal",
			ref:      "refs/tags/v1.0",
			oldOid:   OldOid,
			newOid:   NullSHA1,
			pushopts: map[string]string{"review": "new"},
			expected: "normal",
		},
		{
			desc:     "agit refs/for shall route to agit",
			ref:      "refs/for/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{},
			expected: "agit-flow",
		},
		{
			desc:     "agit refs/drafts shall route to agit",
			ref:      "refs/drafts/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{},
			expected: "agit-flow",
		},
		{
			desc:     "agit refs/for-review shall route to agit",
			ref:      "refs/for-review/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{},
			expected: "agit-flow",
		},
		{
			desc:     "give push option new shall route to trunk-base",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "new"},
			expected: "trunk-base",
		},
		{
			desc:     "give push option smart shall route to trunk-base",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "smart"},
			expected: "trunk-base",
		},
		{
			desc:     "give push option id shall route to trunk-base",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "1"},
			expected: "trunk-base",
		},
		{
			desc:     "turn on trunk mode switch shall route to trunk-base",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{},
			env:      map[string]string{"TRUNK_MODE": "true"},
			expected: "trunk-base",
		},
		{
			desc:     "turn on trunk mode and allow push switch shall route to normal",
			ref:      "refs/heads/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{},
			env:      map[string]string{"TRUNK_MODE": "true", "ALLOW_PUSH": "true"},
			expected: "normal",
		},
		{
			desc:     "mix agit flow ref and push option new shall still route to agit",
			ref:      "refs/for/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "new"},
			expected: "agit-flow",
		},
		{
			desc:     "mix agit flow ref and push option no shall still route to agit",
			ref:      "refs/for/master",
			oldOid:   OldOid,
			newOid:   NewOid,
			pushopts: map[string]string{"review": "no"},
			expected: "agit-flow",
		},
	} {
		t.Run(tc.desc, func(t *testing.T) {
			detector, _ := NewGlobsDetector([]string{"refs/for", "refs/for-review", "refs/drafts"}, []string{"refs/tags"}, []string{"refs/heads"}, []string{"refs/merge-requests"})
			tc.router, _ = NewCodeupRouter(detector)
			command := &protocol.Command{
				RWMutex: sync.RWMutex{},
				GitCommand: protocol.GitCommand{
					OldOID: tc.oldOid,
					NewOID: tc.newOid,
					Ref:    tc.ref,
				},
			}
			for k, v := range tc.env {
				os.Setenv(k, v)
			}
			require.Equal(t, tc.expected, tc.router.routeCommand(context.Background(), command, tc.pushopts, nil))
		})
	}
}
